package com.coder.rental.security;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.NumberWithFormat;
import cn.hutool.core.date.DateTime;
import cn.hutool.jwt.JWTPayload;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.coder.rental.entity.User;
import com.coder.rental.utils.JwtUtil;
import com.coder.rental.utils.RedisUtil;
import com.coder.rental.utils.ResultCode;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

// 用于处理成功认证后逻辑
@Component
public class LoginSuccessHandler implements AuthenticationSuccessHandler {
    @Resource
    private RedisUtil redisUtil;
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication)
            throws IOException, ServletException {

        //设置客户端的响应的内容类型是json
        response.setContentType("application/json;charset=utf-8");

        // 从认证消息中提取用户信息
        // 通常是实现了userDetails的对象
        User user = (User) authentication.getPrincipal();

        // todo 生成token的处理
        // 准备token相关数据并生成token
        Map<String,Object> map=new HashMap<>();
        map.put("username",user.getUsername());
        map.put("userid",user.getId());
        String token= JwtUtil.createToken(map);

        // 解析token获取过期时间，并构建认证结果对象
        // 将token和相关信息封装为 AuthenticationResult对象，并转换为json串返回给客户端
        // 至于客户端怎么知道是什么类型的数据，前面已经做了声明
        NumberWithFormat claim = (NumberWithFormat) JwtUtil
                .parseToken(token).getClaim(JWTPayload.EXPIRES_AT);
        long expireTime= Convert.toDate(claim).getTime();
        AuthenticationResult authenticationResult =new AuthenticationResult(
                user.getId(), ResultCode.SUCCESS,
                token, expireTime);

        //获取一个结果，DisableCircularReferenceDetect表示禁用循环引用检测，避免出现循环引用导致的序列化问题
        String result = JSON.toJSONString(authenticationResult, SerializerFeature.DisableCircularReferenceDetect);
        //通过ServletOutputStream 将数据写入响应体，并发送至客户端
        ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write(result.getBytes(StandardCharsets.UTF_8));
        outputStream.flush();
        outputStream.close();

        // 将token存入Redis，设置过期时间
        String tokenKey="token:"+token;
        long nowTime= DateTime.now().getTime();
        redisUtil.set(tokenKey,token,(expireTime-nowTime)/1000); // 毫秒转秒，与redis的ttl格式匹配
    }
}
